package me.firstapp.search.service.impl;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.lucene.analysis.cn.smart.SmartChineseAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.LongField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import me.firstapp.common.exception.ServiceException;
import me.firstapp.common.exception.StatusHouse;
import me.firstapp.common.exception.StatusObject;
import me.firstapp.common.json.ListObject;
import me.firstapp.common.module.bbs.JsonTopic;
import me.firstapp.common.utils.StrUtils;
import me.firstapp.search.service.TopicSearchService;
import me.firstapp.spi.bbs.TopicService;

@Service
public class TopicSearchServiceImpl implements TopicSearchService {

	@Autowired
	private RedisTemplate<String, Object> redisTemplate;

	@Autowired
	private TopicService topicService;

	@Override
	public void addData() {
		try {
			@SuppressWarnings("unchecked")
			List<JsonTopic> topicList = (List<JsonTopic>) redisTemplate.opsForValue().get("topicList");
			if (topicList == null || topicList.isEmpty()) {
				ListObject<JsonTopic> topicResult = topicService.findSomeTopics(null, null, 1000000);
				topicList = topicResult.getItems();
				redisTemplate.opsForValue().set("topicList", topicList);
			}
			if (topicList != null && !topicList.isEmpty()) {
				// 首先，我们需要定义一个词法分析器。
				// Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_40);
				SmartChineseAnalyzer analyzer = new SmartChineseAnalyzer(Version.LUCENE_40);
				// 第二步，确定索引文件存储的位置
				Directory directory = FSDirectory.open(new File("/tmp/topic_index"));
				// 第三步，创建IndexWriter，进行索引文件的写入。
				IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_40, analyzer);
				IndexWriter iwriter = new IndexWriter(directory, config);
				// 第四步，内容提取，进行索引的存储。
				for (JsonTopic topic : topicList) {
					Document doc = new Document();
					String fieldName = "id";
					IndexableField field = new LongField(fieldName, topic.getId(), Field.Store.YES);
					doc.add(field);

					fieldName = "title";
					field = new TextField(fieldName, topic.getTitle(), Field.Store.YES);
					doc.add(field);

					fieldName = "summary";
					field = new TextField(fieldName, topic.getSummary(), Field.Store.YES);
					doc.add(field);

					fieldName = "content";
					field = new TextField(fieldName, topic.getContent(), Field.Store.YES);
					doc.add(field);
					iwriter.addDocument(doc);
				}
				iwriter.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
			throw new ServiceException(new StatusObject("error", "io异常"));
		} catch (Exception e) {
			e.printStackTrace();
			throw new ServiceException(StatusHouse.COMMON_STATUS_ERROR);
		}
	}

	@Override
	public List<JsonTopic> search(String keyword) {
		List<JsonTopic> result = new ArrayList<>();
		Set<Long> topicIds = new HashSet<>();
		try {
			Directory directory = FSDirectory.open(new File("/tmp/topic_index"));
			// 第一步，打开存储位置
			DirectoryReader ireader = DirectoryReader.open(directory);
			// 第二步，创建搜索器
			IndexSearcher isearcher = new IndexSearcher(ireader);
			// 第三步，类似SQL，进行关键字查询
			// Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_40);
			SmartChineseAnalyzer analyzer = new SmartChineseAnalyzer(Version.LUCENE_40);

			if (StrUtils.isNotNULL(keyword)) {
				QueryParser parser1 = new QueryParser(Version.LUCENE_40, "title", analyzer);
				QueryParser parser2 = new QueryParser(Version.LUCENE_40, "summary", analyzer);
				QueryParser parser3 = new QueryParser(Version.LUCENE_40, "content", analyzer);
				List<QueryParser> parsers = new ArrayList<>();
				parsers.add(parser1);
				parsers.add(parser2);
				parsers.add(parser3);

				for (QueryParser parser : parsers) {
					Query query = parser.parse(keyword);
					ScoreDoc[] hits = isearcher.search(query, null, 1000).scoreDocs;
					for (int i = 0; i < hits.length; i++) {
						Document hitDoc = isearcher.doc(hits[i].doc);
						String idStr = hitDoc.get("id");
						if (StrUtils.isNotNULL(idStr)) {
							Long id = Long.valueOf(idStr);
							topicIds.add(id);
						}
					}
				}
			}
			@SuppressWarnings("unchecked")
			Map<Long, JsonTopic> topicMap = (Map<Long, JsonTopic>) redisTemplate.opsForValue().get("topicMap");
			if (topicMap != null) {
				for (Long topicId : topicIds) {
					JsonTopic topic = topicMap.get(topicId);
					result.add(topic);
				}
			}
			if (topicMap == null) {
				@SuppressWarnings("unchecked")
				List<JsonTopic> topicList = (List<JsonTopic>) redisTemplate.opsForValue().get("topicList");
				for (JsonTopic apiJsonTopic : topicList) {
					for (Long topicId : topicIds) {
						if (apiJsonTopic.getId().equals(topicId)) {
							result.add(apiJsonTopic);
						}
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
			throw new ServiceException(new StatusObject("error", "io异常"));
		} catch (ParseException e) {
			e.printStackTrace();
			throw new ServiceException(StatusHouse.COMMON_STATUS_ERROR);
		}
		return result;
	}

}
